package cn.dt.ymcc.service.imp;

import cn.dt.ymcc.dto.CourserSearchDto;
import cn.dt.ymcc.doc.CourseDoc;
import cn.dt.ymcc.esmapper.HighlightResultMapper;
import cn.dt.ymcc.repository.CourseEsrepository;
import cn.dt.ymcc.result.PageList;
import cn.dt.ymcc.service.ICourseEsService;
import cn.dt.ymcc.vo.AggrsBucket;
import cn.dt.ymcc.vo.EsAggPageList;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class CourseEsServiceImp  implements ICourseEsService {
    @Autowired
    private CourseEsrepository courseEsrepository;
    @Autowired
    private HighlightResultMapper highlightResultMapper;
    @Autowired
    ElasticsearchRestTemplate elasticsearchRestTemplate;
    /**
     * 课程发布保存到es
     * @param doc
     */
    @Override
    public void saveCourse(CourseDoc doc) {
        courseEsrepository.save(doc);
    }

    /**
     * 从es中删除数据
     * @param doc
     */
    @Override
    public void deleteCourse(CourseDoc doc) {
        courseEsrepository.delete(doc);
    }

    /**
     * 1.返回pagelist
     * 2.封装顺序，升序还是降序
     * 3.精确搜索等级
     * 4.价格范围
     * @param dto
     * @return
     */
    @Override
    public PageList<CourseDoc> search(CourserSearchDto dto) {
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();

        //封装排序条件========================
        if(StringUtils.hasLength(dto.getSortField())){
            // dto.getSortField()  xl rq  xp pl
            String sortField = null;
            switch (dto.getSortField().toLowerCase()){
                case "xl": sortField="saleCount";break;
                case "xp": sortField="onlineTime";break;
                case "pl": sortField="commentCount";break;
                case "jg": sortField="price";break;
                case "rq": sortField="viewCount";break;
                default: break;
            }
            if(sortField != null){
                if(StringUtils.hasLength(dto.getSortType())){
                    SortOrder sortOrder = dto.getSortType().equalsIgnoreCase("ASC") ? SortOrder.ASC : SortOrder.DESC;
                    builder.withSort(new FieldSortBuilder(sortField).order(sortOrder));
                }
            }
        }
        //封装分页相关的参数===================  0 代表第一页
        builder.withPageable(PageRequest.of(dto.getPage()-1, dto.getRows()));
        //PageRequest pageRequest = PageRequest.of(dto.getPage()-1, dto.getRows());
        //封装查询条件========================
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //DSL查询  private String keyword;//关键字-------
        if(StringUtils.hasLength(dto.getKeyword())){
            boolQuery.must(QueryBuilders.matchQuery("name",dto.getKeyword()));
        }
        //DSL过滤-----------------
        if(dto.getCourseTypeId() != null){
            boolQuery.filter(QueryBuilders.termQuery("courseTypeId",dto.getCourseTypeId()));
        }
        if(StringUtils.hasLength(dto.getGradeName())){
            boolQuery.filter(QueryBuilders.termQuery("gradeName",dto.getGradeName()));
        }
        if(StringUtils.hasLength(dto.getChargeName())){
            Integer charge = dto.getChargeName() == "免费" ? 1 : 2;
            boolQuery.filter(QueryBuilders.termQuery("charge",charge));
        }
        if(dto.getPriceMin() != null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(dto.getPriceMin()));
        }
        if(dto.getPriceMax() != null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").lte(dto.getPriceMax()));
        }
        //高亮展示：1设置高亮字段。2在高亮字段加前后缀设置为其他颜色或者类型
        NativeSearchQueryBuilder name = builder
                .withHighlightFields(new HighlightBuilder.Field("name")
                    .preTags("<font style= 'color : red'>")
                    .postTags("</font>")
                );
        //聚合展示==========================================================
        //聚合展示数据分析:1.根据根据前端设计返回值为map，key是gradeNameTermsAgg和chargeNameTermsAgg，value分别是对应的list<aggrsBucket>,
        //功能实现：1.处理搜索聚合条件是谁，2.封装成前端需要的数据返回给前端
        //1.处理搜索聚合条件
        /**
         * 添加聚合条件
         */
        builder.addAggregation(AggregationBuilders.terms("gradeNameTermsAgg").field("gradeName"));
        builder.addAggregation(AggregationBuilders.terms("chargeNameTermsAgg").field("chargeName"));
        builder.withQuery(boolQuery);
        //搜索Es  ==========================
        NativeSearchQuery build = builder.build();
        AggregatedPage<CourseDoc> page = elasticsearchRestTemplate.queryForPage(build, CourseDoc.class,highlightResultMapper);
        /*
         *处理聚合返回结果
         * 1.获取聚合并作为map返回
         * 2.获取聚合的条件然后强转成terms
         */
        Map<String, Aggregation> aggregationMap = page.getAggregations().asMap();
        ParsedStringTerms gradeNameTermsAgg = (ParsedStringTerms) aggregationMap.get("gradeNameTermsAgg");
        ParsedStringTerms chargeNameTermsAgg = (ParsedStringTerms) aggregationMap.get("chargeNameTermsAgg");
        List< AggrsBucket> aggrsBuckets = new ArrayList<>();
        gradeNameTermsAgg.getBuckets().forEach(bucket -> {
            String key = bucket.getKeyAsString();
            long docCount = bucket.getDocCount();
            AggrsBucket aggrsBucket = new AggrsBucket(key, docCount);
            aggrsBuckets.add(aggrsBucket);
        });// -->List< AggrsBucket >
        //处理收费规则聚合
        List< AggrsBucket> aggrsBuckets1 = new ArrayList<>();
        chargeNameTermsAgg.getBuckets().forEach(bucket -> {
            String key = bucket.getKeyAsString();
            long docCount = bucket.getDocCount();
            AggrsBucket aggrsBucket = new AggrsBucket(key, docCount);
            aggrsBuckets1.add(aggrsBucket);
        });
        HashMap<Object, Object> map = new HashMap<>();
        map.put("gradeNameTermsAgg",aggrsBuckets);
        map.put("chargeNameTermsAgg",aggrsBuckets1);
        //封装PageList返回 ==================
        return new EsAggPageList(page.getTotalElements(),page.getContent(),map);
    }

}
